from rest_framework.views import APIView
from mysystem.models import Users,Role,Dept
from apps.oauth.models import OAuthWXUser
from apps.mall.models import Goods,OrderInfo
from apps.address.models import Address
from utils.jsonResponse import SuccessResponse,ErrorResponse
from rest_framework import serializers
from utils.common import formatdatetime,float2dot,REGEX_MOBILE,get_parameter_dic,renameuploadimg,getminrandomodernum,geturlpath,ismoney,ast_convert,getrandomodernum,format_wechat_gmt_8_to_normal,formatdatetime_convert
import re
from django.db.models import Q,F,Sum, Avg, Max, Min, Count
from rest_framework.serializers import ModelSerializer
from rest_framework_simplejwt.authentication import JWTAuthentication
from utils.serializers import CustomModelSerializer
from utils.viewset import CustomModelViewSet
from rest_framework.permissions import IsAuthenticated
from utils.filters import FinanceOrderInfoTimeFilter
from django.db import transaction
from django_redis import get_redis_connection
import os
import json
from django.contrib.auth.hashers import make_password
from decimal import Decimal
from utils.export_excel import export_excel
from utils.pagination import CustomPagination
from utils.wexinpay_cashout import Pay,get_client_ip,random_str
from utils.weixinpay import WxAppPay
from utils.alipay import initalipay,alipay_trade_app,alipay_trade_refund
from config import DOMAIN_HOST
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from django.http import HttpResponse
import logging
logger = logging.getLogger(__name__)
from datetime import datetime, timedelta, date

# Create your views here.
# ================================================= #
# ************** 后端商城管理 view  ************** #
# ================================================= #

class GoodsManageSerializer(CustomModelSerializer):
    """
    商品分类管理-序列化器
    """
    class Meta:
        model = Goods
        read_only_fields = ["id"]
        fields = '__all__'

class GoodsManageViewSet(CustomModelViewSet):
    """
    后台商品分类管理 接口
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsManageSerializer
    search_fields = ('name',)
    filterset_fields = ('status',)

    def islaunched(self, request, *args, **kwargs):
        """上下架商品"""
        queryset = self.filter_queryset(self.get_queryset())
        pk = kwargs.get('pk')
        if ',' in kwargs.get('pk'):  # 批量
            ids = pk.split(',')
            instance = queryset.filter(id__in=ids)
            if instance:
                instance.update(status=True)
                return SuccessResponse(data=None, msg="修改成功")
            else:
                return ErrorResponse(msg="未获取到该商品")
        else:
            instance = Goods.objects.filter(id=kwargs.get('pk')).first()
            if instance:
                if instance.status:
                    instance.status = False
                else:
                    instance.status = True
                instance.save()
                return SuccessResponse(data=None, msg="修改成功")
            else:
                return ErrorResponse(msg="未获取到该商品")
            
class FinanceOrderInfoSerializer(CustomModelSerializer):
    """
    商品类财务流水-序列化器
    """
    userinfo = serializers.SerializerMethodField()
    pay_method = serializers.SerializerMethodField()
    gname = serializers.SerializerMethodField()

    def get_gname(self,obj):
        allgoods = obj.ordergoodsskus.all().first()
        return allgoods.sku.spu.name


    def get_pay_method(self,obj):
        return obj.get_pay_method_display()

    def get_userinfo(self, obj):
        return {
            'id': obj.user.id,
            'nickname': obj.user.nickname,
            'avatar': obj.user.avatar
        }

    class Meta:
        model = OrderInfo
        read_only_fields = ["id"]
        fields = '__all__'

class FinanceOrderInfoViewSet(CustomModelViewSet):
    """
    后台会商品类财务流水 接口
    """
    queryset = OrderInfo.objects.filter(pay_status=1).order_by("-create_datetime")
    serializer_class = FinanceOrderInfoSerializer
    # search_fields = ('name',)
    filterset_class = FinanceOrderInfoTimeFilter

    def orderstatistics(self,request):
        """
        订单金额 收益总金额统计
        :param request:
        :return:
        """
        #按照原来的过滤查询
        queryset = self.filter_queryset(self.get_queryset())
        totalmoney = 0
        if queryset:
            totalmoney = queryset.aggregate(price = Sum('total_amount'))['price']
        else:
            totalmoney = 0

        data = {
            "totalmoney": float2dot(totalmoney),
        }

        return SuccessResponse(data=data,msg='success')
    
class OrderInfoSerializer(CustomModelSerializer):
    #address = serializers.SerializerMethodField(read_only=True)
    userinfo = serializers.SerializerMethodField(read_only=True)
    #goodsinfo = serializers.SerializerMethodField(read_only=True)
    pay_time = serializers.SerializerMethodField(read_only=True)
    pay_method_name = serializers.SerializerMethodField(read_only=True)

    def get_pay_time(self,obj):
        return formatdatetime(obj.pay_time)

    def get_pay_method_name(self,obj):
        return obj.get_pay_method_display()
    '''
    def get_goodsinfo(self,obj):
        data=[]
        goods = OrderGoods.objects.filter(order_id=obj.id)
        if not goods:
            return None
        for good in goods:
            datasku={}
            if good.sku.spu.spec_type == 1:#多规格
                sku_spec = ""
                temp_sepcs = good.sku.specs.all()
                for temp_sepc in temp_sepcs:
                    if len(temp_sepcs) > 1:
                        sku_spec = sku_spec + temp_sepc.option.value + ';'
                    else:
                        sku_spec = temp_sepc.option.value

            else:
                sku_spec = good.sku.spu.name
            datasku['sku_name'] = good.sku.name
            datasku['sku_spec'] = sku_spec
            datasku['sku_default_image'] = good.sku.default_image
            datasku['count'] = good.count
            datasku['price'] = good.price
            datasku['comment'] = good.comment
            datasku['score'] = good.score
            data.append(datasku)
        return data
    '''
    def get_address(self,obj):
        data={}
        data['areas'] = obj.address.get_region_format()+ (obj.address.street if obj.address.street else "")  + obj.address.place
        data['receiver'] = obj.address.receiver
        data['mobile'] = obj.address.mobile
        return data

    def get_userinfo(self, obj):
        return {
            'id': obj.user.id,
            'nickname': obj.user.nickname,
            'name':obj.user.name,
            'avatar': obj.user.avatar,
            'mobile':obj.user.mobile,
        }

    class Meta:
        model = OrderInfo
        fields = "__all__"
        read_only_fields = ["id"]

class GoodsOrderManageViewSet(CustomModelViewSet):
    """
    商品订单管理:
    list:查询
    create:新增
    update:修改
    retrieve:单例
    destroy:删除
    """
    queryset = OrderInfo.objects.all().order_by('-create_datetime')
    serializer_class = OrderInfoSerializer
    filterset_class = FinanceOrderInfoTimeFilter

    def closeorder(self,request):
        # 按照原来的过滤查询
        queryset = self.filter_queryset(self.get_queryset())
        # 接收的参数
        id = get_parameter_dic(request)['id']  # 商品订单id
        if not id:
            return ErrorResponse(msg="提交的参数不能为空")
        order = queryset.filter(id=id, status=2).first()
        if not order:
            return ErrorResponse(msg='不存在此商品订单信息,或该状态订单不支持关闭')

        with transaction.atomic():
            order.status = 6
            order.save()
            # 订单退款逻辑
            #orderrefund()
            return SuccessResponse(msg='订单已关闭')

    def orderstatistics(self,request):
        """
        订单金额 订单量统计
        :param request:
        :return:
        """
        #按照原来的过滤查询
        queryset = self.filter_queryset(self.get_queryset())
        totalmoney = 0
        totalcount = 0
        if queryset:
            totalmoney = queryset.aggregate(price = Sum('total_pay'))['price']
            totalcount = queryset.count()
        data = {
            "totalmoney": float2dot(totalmoney),
            "totalcount": totalcount,
        }
        return SuccessResponse(data=data,msg='success')

    def orderstatus(self,request):
        # 按照原来的过滤查询
        queryset = self.filter_queryset(self.get_queryset())
        id = get_parameter_dic(request)['id']  # 商品订单id
        status = get_parameter_dic(request)['status']  # 商品物流单号
        if not all([id,status]):
            return ErrorResponse(msg="提交的参数不能为空")
        order = queryset.filter(id=id).first()
        if not order:
            return ErrorResponse(msg='不存在此商品订单信息,')
        if order.status ==1 and status ==2:
            order.pay_status = 1
        order.status = status
        order.save()
        return SuccessResponse(msg='success')

    def ordersrefund(self,request):
        # 按照原来的过滤查询
        queryset = self.filter_queryset(self.get_queryset())
        id = get_parameter_dic(request)['id']  # 商品订单id
        status = get_parameter_dic(request)['status']  # 商品订单id
        if not all([id]):
            return ErrorResponse(msg="提交的参数不能为空")
        order = queryset.filter(id=id,pay_status=2).first()
        if not order:
            return ErrorResponse(msg='不存在此商品订单信息,')
        if status==7:
            try:
                wxapppay = WxAppPay()
                data=wxapppay.refundsorder(getrandomodernum(),order.trade_id,"用户取消出行",order.total_pay*100,order.total_pay*100)
                if(data["status"]=="SUCCESS" or data["status"]=="PROCESSING"):
                    order.pay_status = 4
                    order.status = 6
                    order.save()
                else:
                    logger.info("修改")
            except Exception as e:
                logger.info("777")
                logger.info(e)
        else:
            order.pay_status = 2
            order.save()
        
        return SuccessResponse(msg='success')

    def sendoutgoods(self,request):
        # 按照原来的过滤查询
        queryset = self.filter_queryset(self.get_queryset())
        #接收的参数
        id = get_parameter_dic(request)['id']  # 商品订单id
        orderNo = get_parameter_dic(request)['orderNo']  # 商品物流单号
        logistics_company = get_parameter_dic(request)['logistics_company']  # 商品物流公司
        if not all([id,orderNo,logistics_company]):
            return ErrorResponse(msg="提交的参数不能为空")
        order = queryset.filter(id=id,status=2).first()
        if not order:
            return ErrorResponse(msg='不存在此商品订单信息,或该状态订单不支持发货')
        order.logistics_id = orderNo
        order.logistics_company = logistics_company
        order.send_time = datetime.datetime.now()
        order.status = 3
        order.save()
        return SuccessResponse(msg='修改成功')


# ================================================= #
# ************** 前端商城接口 view  ************** #
# ================================================= #

class GoodsListView(APIView):
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]
    def get(self,request):
        start = get_parameter_dic(request).get('start')  # 搜索
        end = get_parameter_dic(request).get('end')  # 搜索
        date1 = get_parameter_dic(request).get('date')  # 搜索
        queryset = Goods.objects.filter(status__contains=1)
        # # 1. 实例化分页器对象
        page_obj = CustomPagination()
        # # 2. 使用自己配置的分页器调用分页方法进行分页
        page_data = page_obj.paginate_queryset(queryset, request)
        data = []
        result = []
        now_time = datetime.now()

        time_obj = formatdatetime_convert(date1)
        current_date = date.today()

        if(current_date.strftime('%Y-%m-%d')>time_obj.strftime('%Y-%m-%d')):#大于今天日期返回空
            return page_obj.get_paginated_response(data=[])
        #logger.info("收到微信支付回调通知时间:%s" % (now_time))
        result= [{'id':m.id,'name':m.name,'nums':m.nums, 'times':formatdatetime_convert(date1+" "+t.strip()+":00"),'stations':m.stations,'prices':m.prices,'status':m.status} for m in page_data for t in m.times if time_obj.strftime('%Y-%m-%d %H:%M:%S')<=formatdatetime_convert(date1+" "+t.strip()+":00").strftime('%Y-%m-%d %H:%M:%S')]
        for m in result:
            item={'id':m["id"],'name':m["name"], 'nums':m["nums"], 'times':m["times"],'stations':m["stations"], 'prices':[],'status':m["status"]}
            for index,mdata in enumerate(m["prices"]):
                time_obj="00:00:00"
                kk=0
                if not mdata["time"]:
                    mdata["time"]=0
                time_obj = formatdatetime_convert(m["times"])
                time_obj = time_obj+timedelta(minutes=int(mdata["time"]))
                if not isinstance(time_obj, str): kk=(time_obj-now_time).total_seconds()
                if kk<1:continue
                item['prices'].append({
                    'id':m["id"],
                    'line_id':index,
                    'start':mdata["start"],
                    'end':mdata["end"],
                    'time':time_obj,
                    'price':mdata["price"],
                    'mprice':mdata["mprice"]
                })
            data.append(item)
        if start.strip()=="" or end.strip()=="":
            #data=[items for items in data for item in items["prices"] if len(start.strip())>0 and len(end.strip())>0 and item["start"].strip()==start.strip() and item["end"].strip()==end.strip()]
            data=[items for items in data for item in items["prices"]]
        else:
            data=[{'id':items["id"],'name':items["name"],'nums':items["nums"], 'times':items['times'],'stations':items['stations'],'status':items['status'],'prices':[item]}
                for items in data for item in items["prices"] if len(start.strip())>0 and len(end.strip())>0 and item["start"].strip()==start.strip() and item["end"].strip()==end.strip()]
    
        return page_obj.get_paginated_response(data=data)

class GoodsOrdersListView(APIView):
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]

    def get(self,request):
        user = request.user
        status = get_parameter_dic(request).get('status')
        search = get_parameter_dic(request).get('search')
        if search:
            if status:
                queryset = OrderInfo.objects.filter(user=user, order_id__contains=search,is_delete=False,status=int(status)).order_by('-create_datetime')
            else:
                queryset = OrderInfo.objects.filter(user=user, order_id__contains=search,is_delete=False).exclude(status=1).order_by('-create_datetime')
        else:
            if status:
                queryset = OrderInfo.objects.filter(user=user,is_delete=False,status=int(status)).order_by('-create_datetime')
            else:
                queryset = OrderInfo.objects.filter(user=user, is_delete=False).exclude(status=1).order_by('-create_datetime')
        # # 1. 实例化分页器对象
        page_obj = CustomPagination()
        # # 2. 使用自己配置的分页器调用分页方法进行分页
        page_data = page_obj.paginate_queryset(queryset, request)
        data = []
        if queryset:
            for m in page_data:
                data.append({
                    'id': m.id,
                    'orderNo': m.order_id,
                    'orderStatus': m.status,
                    'orderStatusName':m.get_status_display(),
                    'pay_status':m.pay_status,
                    'payStatusName':m.get_pay_status_display(),
                    'amount':m.total_pay,
                    'buttonVOs':[],
                    'goodsInfo':{
                        'times':m.times,
                        'start':m.start,
                        'end':m.end,
                        'bnum':m.count,
                        'price':m.price,
                    },
                    'remark':m.remark,
                    'createTime':formatdatetime(m.create_datetime)
                })
        return page_obj.get_paginated_response(data=data)

#确认上车
class OrdersConfimView(APIView):
    def post(self, request):
        order_id = get_parameter_dic(request).get('id')
        order = OrderInfo.objects.filter(user=request.user,id=order_id).first()
        if order:
            if order.status ==2:
                order.status = 3
                if order.pay_status >0:order.pay_status = 1
                order.save()
                return SuccessResponse(msg="success")
            return ErrorResponse(msg='订单不是在等待上车状态')
        return ErrorResponse(msg='订单不存在')

#取消出行
class OrdersRefundView(APIView):
    def post(self, request):
        order_id = get_parameter_dic(request).get('id')
        order = OrderInfo.objects.filter(user=request.user,id=order_id).first()
        if order:
            if order.status ==2:
                order.status = 6
                if order.pay_status ==1:
                    wxapppay = WxAppPay()
                    wxapppay.refundsorder(getrandomodernum(),order.trade_id,"用户取消出行",order.total_pay*100,order.total_pay*100)
                    order.pay_status = 2
                order.save()
                return SuccessResponse(msg="success")
            return ErrorResponse(msg='已上车不能取消出行')
        return ErrorResponse(msg='订单不存在')

class OrdersServiceView(APIView):
    def post(self, request):
        order_id = get_parameter_dic(request).get('id')
        order = OrderInfo.objects.filter(user=request.user,id=order_id).first()
        if order:
            if (order.status ==3 or order.status ==4):
                if order.pay_status ==1:
                    order.pay_status = 2
                    order.save()
                    return SuccessResponse(msg="success")
                return ErrorResponse(msg='订单不是已支付状态')
            return ErrorResponse(msg='没有出行,不能申请退款')
        return ErrorResponse(msg='订单不存在')

class OrdersRevokeView(APIView):
    def post(self, request):
        order_id = get_parameter_dic(request).get('id')
        order = OrderInfo.objects.filter(user=request.user,id=order_id).first()
        if order and (order.pay_status == 2 or order.pay_status == 3):
            order.pay_status = 1
            order.save()
            return SuccessResponse(msg="success")
        return ErrorResponse(msg='订单不存在,或不是已支付状态')

    
class OrdersCommitView(APIView):
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]
    def post(self, request):
        goods_id = get_parameter_dic(request)['goods_id']
        line_id = int(get_parameter_dic(request)['line_id'])
        times = get_parameter_dic(request)['times']
        mobile = get_parameter_dic(request)['mobile']
        nums = int(get_parameter_dic(request)['nums'])
        remark = get_parameter_dic(request)['remark']

        if not goods_id:
            return ErrorResponse(msg='购买的车票不存在')
        if nums <= 0:
            return ErrorResponse(msg='购买的车票数量错误')
        goods = Goods.objects.filter(id=goods_id, status=True).first()
        
        if not goods:
            return ErrorResponse(msg='不存在该车次，或该车次暂不支持购买')
        if not remark:
            remark = ""
        user = request.user
        # 生成订单编号
        order_id = getrandomodernum()
        # 开启事物
        with transaction.atomic():
            try:
                # 设置保存点
                save_point = transaction.savepoint()
                orders = OrderInfo.objects.filter(goods_id=goods_id, times=times)
                if orders.count()>=goods.nums:
                    return ErrorResponse(msg='订单数量超过了')
                # 生成订单的基本信息
                order = OrderInfo.objects.create(
                    goods_id=goods_id,
                    order_id=order_id,
                    user=user,
                    remark=remark,
                    start=goods.prices[line_id]["start"],
                    end = goods.prices[line_id]["end"],
                    price=goods.prices[line_id]["price"],
                    times=times,
                    mobile=mobile,
                    count=nums,
                    status=1,
                    pay_status=0,
                )
                order.total_pay = order.price*order.count
                order.save()
            except Exception as e:
                logger.info(e)
                # 回滚到保存点
                transaction.savepoint_rollback(save_point)
                return ErrorResponse(msg='请稍后再试')
            else:
                # 事物结束提交数据
                transaction.savepoint_commit(save_point)
            return SuccessResponse(data={'id': order.id,'order_id': order.order_id},msg='success')

class PaymentView(APIView):
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]

    def post(self, request):
        user = request.user
        if user.identity !=2:
            return ErrorResponse(msg="用户类型错误")
        paymethod = int(get_parameter_dic(request)['pay_method'])
        platform = get_parameter_dic(request).get('platform')
        paytype = get_parameter_dic(request)['pay_type']
        if platform and platform not in ['app','xcx']:
            return ErrorResponse(msg="platform类型错误")
        if not platform:
            platform = 'app'
        if paymethod not in [2,3]:
            return ErrorResponse(msg="paymethod类型错误")
        money = 0
        #业务逻辑
        with transaction.atomic():
            # 设置保存点
            save_point = transaction.savepoint()
            try:
                orderno = getminrandomodernum()
                #其他业务逻辑
                id = get_parameter_dic(request)['id']
                if not id: return ErrorResponse(msg='id error1')
                order = OrderInfo.objects.filter(id=id,user=user,pay_status=0).first()
                if not order: return ErrorResponse(msg='id error2')
                money = order.total_pay
                orderno = order.order_id
                order.pay_method = paymethod
                order.save()

                #支付类型判断
                if paymethod == 2:
                    wxapppay = WxAppPay()
                    if platform == 'app':#app支付
                        data = wxapppay.payorder(orderno, money * 100, orderno,paytype,notify_url="%s/api/app/wechatpay_notify/" % DOMAIN_HOST)  # 要填写回调地址
                    else:
                        openid = OAuthWXUser.objects.filter(user=user).values_list('xcx_openid', flat=True).first()
                        if not openid:
                            # 回滚到保存点
                            transaction.savepoint_rollback(save_point)
                        data = wxapppay.payorder_jsapi(orderno, money * 100, orderno,paytype,openid,notify_url="%s/api/app/wechatpay_notify/" % DOMAIN_HOST)  # 要填写回调地址
                    # 事物结束提交数据
                    transaction.savepoint_commit(save_point)
                    return SuccessResponse(data={'id': order.id, 'order_no': order.order_id, 'paymethod': 2, 'paystatus': order.pay_status,'wechataydata': data}, msg="success")
                elif paymethod == 3:
                    data = alipay_trade_app(orderno, float(money),notify_url="%s/api/app/alipay_notify/" % DOMAIN_HOST)
                    # 事物结束提交数据
                    transaction.savepoint_commit(save_point)
                    return SuccessResponse(data={'order_no':order.order_id,'alipaydata':data}, msg="success")
                return ErrorResponse(msg="paytype类型错误")
            except Exception as e:
                transaction.savepoint_rollback(save_point)
                return ErrorResponse(msg=str(e))

class wechatpay_notify(APIView):
    """
    支付成功后，微信服务器异步通知回调（用于修改订单状态）
    """
    def post(self,request):
        wxpay = WxAppPay()
        result = wxpay.decrypt_callback(request)
        logger.info("收到微信支付回调通知:%s" % (result))
        if result:
            """
            {"mchid":"1617830805","appid":"wx023a7d62457e3803","out_trade_no":"20220112163528260904706","transaction_id":"4200001335202201122963662545","trade_type":"JSAPI","trade_state":"SUCCESS","trade_state_desc":"支付成功","bank_type":"CMBC_DEBIT","attach":"","success_time":"2022-01-12T16:35:42+08:00","payer":{"openid":"ocBnz4pg2G05LaUFpNE9bxR2B88w"},"amount":{"total":1,"payer_total":1,"currency":"CNY","payer_currency":"CNY"}}
            """
            resp = json.loads(result)
            appid = resp.get('appid')
            mchid = resp.get('mchid')
            out_trade_no = resp.get('out_trade_no')
            transaction_id = resp.get('transaction_id')
            trade_type = resp.get('trade_type')
            trade_state = resp.get('trade_state')
            trade_state_desc = resp.get('trade_state_desc')
            bank_type = resp.get('bank_type')
            attach = resp.get('attach')#自定义数据
            success_time = format_wechat_gmt_8_to_normal(resp.get('success_time'))
            payer = resp.get('payer')
            amount = (resp.get('amount').get('total'))/100
            # TODO: 根据返回参数进行必要的业务处理，处理完后返回200或204
            if trade_state == "SUCCESS":  # 支付成功
                # 查询数据库中存在的订单
                order = OrderInfo.objects.filter(order_id=out_trade_no, pay_status=0, pay_method=2).first()
                if not order:
                    logger.info("处理收到微信支付回调通知:%s，没有找到该订单" % (result))
                    return HttpResponse('fail')
                order.trade_id = transaction_id
                order.pay_status = 1
                order.pay_time = success_time
                order.save()
                # 其他逻辑处理
                orderpaysuccess(order.id)
                return HttpResponse('success')
            else:
                return HttpResponse('fail')
        else:
            return HttpResponse('fail')

#用户支付成功处理对应逻辑
def orderpaysuccess(order_id):
    """
    order：订单order的id(内部订单编号)
    """
    order = OrderInfo.objects.get(id=order_id)
    order.status = 2
    order.save()
    #支付成功其他业务处理